import { Subject, Subscription } from "rxjs";
import { RxOp } from "./ReactiveOp";

import { _decorator } from 'cc';
const { ccclass, property } = _decorator;

@ccclass
export class ReactiveList<T> {

    static Create<T>(): ReactiveList<T> {
        return new ReactiveList<T>().init();
    }

    list: Array<T>;

    _subject: Subject<{ op: RxOp, v?: T }> = null;

    init(): ReactiveList<T> {
        this.list = [];
        this._subject = new Subject<{ op: RxOp, v?: T }>();
        return this;
    }

    get value(): Array<T> {
        return this.list;
    }

    set value(value: Array<T>) {
        this.list = [];
        for (let i = 0; i < value.length; i++) {
            this.list.push(value[i]);
            this._subject.next({ op: RxOp.init, v: value[i] });
        }
    }

    push(item: T): void {
        this.list.push(item);
        this._subject.next({ op: RxOp.push, v: item });
    }

    pop(): T {
        let item = this.list.pop();
        this._subject.next({ op: RxOp.pop, v: item });
        return item;
    }

    unshift(item: T): void {
        this.list.unshift(item);
        this._subject.next({ op: RxOp.unshift, v: item });
    }

    shift(): T {
        let item = this.list.shift();
        this._subject.next({ op: RxOp.shift, v: item });
        return item;
    }

    clear() {
        this.list = [];
        this._subject.next({ op: RxOp.clear });
    }

    replace(condition: (value: T, index: number, obj: T[]) => unknown, ...items: T[]) {
        let index = this.list.findIndex(condition);
        if (index >= 0) {
            this.list.splice(index, 1, ...items);
            this._subject.next({ op: RxOp.replace });
        }
    }

    customHandle(handler: (list: Array<T>) => boolean) {
        if (handler(this.list)) {
            this._subject.next({ op: RxOp.custom });
        }
    }

    subscribe(callback: (value: { op: RxOp, v?: T }) => void): Subscription {
        return this._subject.subscribe(callback);
    }
}
